/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.commonmodel.spi;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IEntityDataCollection;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.extend.entity.ICefAddedChildEntityExtend;
import com.inspur.edp.cef.spi.extend.entity.ICefEntityExtend;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefDataDeSerializer;
import com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefDataSerItem;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.cef.spi.jsonser.builtinimpls.CefEntityDataSerializerItem;
import com.inspur.edp.cef.spi.jsonser.entity.AbstractEntitySerializerItem;
import com.inspur.edp.commonmodel.api.ICMManager;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public abstract class AbstractEntityDataDeSerializer extends AbstractCefDataDeSerializer
{
  private String objectCode;
  private boolean isRoot;
  private ICMManager manager;

  protected AbstractEntityDataDeSerializer(String objectCode, boolean isRoot, List<AbstractEntitySerializerItem> serializers) {
    super(serializers);
    this.objectCode = objectCode;
    this.isRoot = isRoot;
  }

  @Override
  protected ICefData createData(JsonParser reader) {
    String dataId = null;
    try {
      String key = reader.getValueAsString();
      //12.03 广水要求支持第一个参数不是id, 需要兼容第一个参数不是"dataId"或主键标签的场景:
      if("dataId".equalsIgnoreCase(key) || "id".equalsIgnoreCase(key) || !containPropInfo(key)) {
        reader.nextToken();
        dataId = reader.getValueAsString();
        ICefData result = isRoot ? getCMManager().createUnlistenableData(dataId)
            : getCMManager().createUnlistenableChildData(objectCode, dataId);
        reader.nextToken();
        return result;
      } else {
        return isRoot ? getCMManager().createUnlistenableData(dataId)
            : getCMManager().createUnlistenableChildData(objectCode, dataId);
      }
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private boolean containPropInfo(String key){
    CefEntityDataSerializerItem item = (CefEntityDataSerializerItem) getSerializerItems()
        .stream().findFirst().orElse(null);
    if (item != null && item instanceof CefEntityDataSerializerItem) {
      return ((CefEntityDataSerializerItem) item).getResInfo()
          .getEntityTypeInfo().containsPropertyInfo(key);
    } else {
      return false;
    }
  }

//  protected abstract ICMManager getCMManager();

  protected ICMManager getCMManager() {
    return manager;
  }

  public void setManager(ICMManager manager){
    this.manager = manager;
  }

  @Override
  protected void readDataInfo(JsonParser reader, DeserializationContext ctxt, ICefData data, String propertyName)
  {
    if (reader.getCurrentToken() == JsonToken.START_ARRAY)
    {
      //TODO:基类方法增加throw ioException这里去掉try
      try {
        readEntityChild(reader, ctxt, propertyName, (IEntityData)data);
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }
    else
    {
      super.readDataInfo(reader, ctxt, data, propertyName);
    }
  }

  private void readEntityChild(JsonParser reader, DeserializationContext ctxt, String childCode, IEntityData data)
      throws IOException {
    String realCode = getRealChildCode(childCode);
    AbstractEntityDataDeSerializer childConvertor = innerGetChildConvertor(realCode);
    //DataValidator.CheckForNullReference(childConvertor, String.format("编号为%1$s的子表转换器", childCode));
    IEntityDataCollection childs = data.getChilds().get(childConvertor.objectCode);
    while (reader.hasCurrentToken())
    {
      reader.nextToken();
      if (reader.getCurrentToken() == JsonToken.END_ARRAY)
      {
        break;
      }
      IEntityData childData = (IEntityData)childConvertor.readJson(reader, ctxt);
      childs.add(childData);
    }
  }

  protected String getRealChildCode(String propertyName) {

    Class entityType = getCMManager().createData("").getClass();
    String transNodeCode = propertyName.substring(0, propertyName.length()  - 1);
    if (!propertyName.equals(StringUtils.toCamelCase(propertyName)))
      return transNodeCode;

    for(Method method :entityType.getMethods()) {
      //if (!propertyInfo.GetCustomAttributes(typeof(VMChildAttribute), true).Any())
      //    continue;
      if(method.getReturnType() != IEntityDataCollection.class)
        continue;
      String methodName = method.getName();
      String tansCode = methodName.substring(0, methodName.length() - 1).substring(3);
      if (StringUtils.toCamelCase(tansCode).equals(transNodeCode )|| tansCode.equals(transNodeCode))
        return tansCode;
    }
    return propertyName.substring(0, propertyName.length() - 1);
  }

  private AbstractEntityDataDeSerializer innerGetChildConvertor(String nodeCode){
    for(Object item : getExtendList()) {
      List<ICefAddedChildEntityExtend> addedChilds = ((ICefEntityExtend)item).getAddedChilds();
      if(addedChilds == null){
        continue;
      }
      for(ICefAddedChildEntityExtend addedChild : addedChilds){
        if(addedChild.getNodeCode().equals(nodeCode)){
          return (AbstractEntityDataDeSerializer)addedChild.getDataDeserializer();
        }
      }
    }
    return buildChildConvertor(nodeCode);
  }

  protected abstract AbstractEntityDataDeSerializer getChildConvertor(String childCode);

  protected AbstractEntityDataDeSerializer buildChildConvertor(String childCode){
    AbstractEntityDataDeSerializer childConvertor = getChildConvertor(childCode);
    childConvertor.setManager(getCMManager());
    return childConvertor;
  }

  public AbstractEntityDataDeSerializer getChildDataConvertor(String childCode){
    return buildChildConvertor(childCode);
  }
}
